package cn.itcast.nems.studentrecord.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.EnumUtil;
import cn.itcast.nems.common.constant.PaymentTypeEum;
import cn.itcast.nems.common.util.EducationEnum;
import cn.itcast.nems.common.util.IDCardUtil;
import cn.itcast.nems.common.util.LocalDateTimeUtils;
import cn.itcast.nems.manager.util.CustomBeanUtil;
import cn.itcast.nems.oldems.dto.*;
import cn.itcast.nems.product.dao.dataobject.ProductDO;
import cn.itcast.nems.studentrecord.constant.ContractStateEnum;
import cn.itcast.nems.studentrecord.constant.ReferenceTypeEnum;
import cn.itcast.nems.studentrecord.dao.dataobject.StudentRecordDO;
import cn.itcast.nems.studentrecord.dao.entity.JournalDropout;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecord;
import cn.itcast.nems.studentrecord.dto.StudentRecordInfoDTO;
import cn.itcast.nems.studentrecord.dto.StudentRecordRefundInfoDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

public class StudentRecordInfoServiceUtil {
    private final static Logger log = LoggerFactory.getLogger(StudentRecordInfoServiceUtil.class);

    private StudentRecordInfoServiceUtil() {
    }
    public static void convertToStudentInfoDTO(StudentInfoDTO studentInfoDTO,
                                               Map<Integer, List<StudentRecordDO>> studentRecordClazzMap,
                                               Map<Integer, List<StudentBelongerDTO>> belongerMap) {

        // 学历名称
        studentInfoDTO.setEducation(EnumUtil.getFieldBy(EducationEnum::getName,EducationEnum::name,studentInfoDTO.getEducationCode() ) );
        // 手机号 脱敏
        studentInfoDTO.setPhone(DesensitizedUtil.mobilePhone(studentInfoDTO.getPhone()));
        // 是否成年
        int age = IDCardUtil.getAge(studentInfoDTO.getIdcard() , studentInfoDTO.getBirthday());
        studentInfoDTO.setIsAdult(IDCardUtil.isAdult(studentInfoDTO.getIdcard(), new Date()));
        studentInfoDTO.setAgeRank(IDCardUtil.ageRank(age));
        // 当前所在班级
        setCurrentClazz(studentInfoDTO, studentRecordClazzMap);
        if (belongerMap.containsKey(studentInfoDTO.getId())) {
            List<StudentBelongerDTO> belongerList = belongerMap.get(studentInfoDTO.getId());
            studentInfoDTO.setCollegeBelongerName(belongerList.get(0).getRealName());
            studentInfoDTO.setCollegeBelongerNumber(belongerList.get(0).getJobNumber());
        }

    }

    /**
     * 针对Tlias 根据学生ID查询学籍详情， 响应正文字段【当前所在班级】获取逻辑， 参考如下执行顺序：
     * 1、过滤 当天进当天出的学籍 ，  如果学籍列表为空，直接返回 吗，否则执行下一步  ；
     * 2、满足  【学籍入班时间】<=【当前时间】, 且 【学籍出班时间】为空或【学籍出班时间】>= 【当前时间】 ， 取该学籍对应的班级ID  ；
     * 3、存在未来【入班时间】的学籍 ，即【入班时间】> 【当前时间】，且【学籍出班时间】为空或【学籍出班时间】> 【当前时间】的学籍，    取【入班时间】最接近【当前时间】学籍对应的班级ID  ；
     * 4、不存在未来【入班时间】的学籍， 但是存在已出班的学籍 ， 取【出班时间】最接近【当前时间】学籍应的班级ID 。
     * 5、判断的当前就读班级的【学籍来源】是否为【休学】   ，如果是且学籍【关联学籍ID】不为空， 取【关联学籍ID】对应的班级ID
     *
     * @param studentInfoDTO 学生信息
     * @param studentRecordClazzMap 学生ID对应的学籍列表
     */
    private static void setCurrentClazz(StudentInfoDTO studentInfoDTO,
                                        Map<Integer, List<StudentRecordDO>> studentRecordClazzMap) {
        // 不存在学籍 ，学籍列表为空，直接返回
        if (!studentRecordClazzMap.containsKey(studentInfoDTO.getId())) {
            log.info("【获取当前所在班级】不存在历史学籍，班级学籍详情：{} ", JSON.toJSONString(studentInfoDTO , SerializerFeature.DisableCircularReferenceDetect));
            return;
        }
        int result = 0;
        LocalDateTime currentDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        // 过滤所有当天进、当天出的学籍
        List<StudentRecordDO> studentRecordList = Objects.requireNonNullElse(studentRecordClazzMap.get(studentInfoDTO.getId()),new ArrayList<StudentRecordDO>())
                .stream()
                .filter(item -> !item.getInDate().equals(item.getSettlementDate()))
                .toList();
        // 1、判断条件：【学籍入班时间】<=【当前时间】, 且 【学籍出班时间】为空或【学籍出班时间】>= 【当前时间】
        StudentRecordDO studentRecordDO = studentRecordList.stream()
                .filter(item -> {
                    LocalDateTime inDate = item.getInDate();
                    LocalDateTime settlementDate = item.getSettlementDate();
                    return  !inDate.isAfter(currentDateTime) && (Objects.isNull(settlementDate) || !settlementDate.isBefore(currentDateTime));
                })
                .peek(item -> item.setSort(Objects.nonNull(item.getSettlementDate())?1:0))
                .max(Comparator.comparing(StudentRecordDO::getSort)).orElse(null);
        result = Objects.nonNull(studentRecordDO) ? 1 : result;
        // 2、存在未来【入班时间】的学籍 ，【入班时间】>【当前时间】，且【学籍出班时间】为空或【学籍出班时间】> 【当前时间】的学籍，取【入班时间】最接近【当前时间】学籍对应的班级ID
        StudentRecordDO studentRecordDO2 = result > 0 ? null : studentRecordList.stream()
                .filter(item -> {
                            LocalDateTime inDate = item.getInDate();
                            LocalDateTime settlementDate = item.getSettlementDate();
                            return inDate.isAfter(currentDateTime) && (Objects.isNull(settlementDate) || settlementDate.isAfter(currentDateTime));
                        }
                )
                .peek(item -> item.setInterval(LocalDateTimeUtils.betweenTwoTime(currentDateTime, item.getInDate(), ChronoUnit.SECONDS)))
                .min(Comparator.comparing(StudentRecordDO::getInterval)).orElse(null);
        result = Objects.nonNull(studentRecordDO2) ? 2 : result;
        // 3、不存在未来【入班时间】的学籍， 但是存在已出班的学籍 ， 取【出班时间】最接近【当前时间】学籍应的班级ID
        StudentRecordDO studentRecordDO3 = result > 0 ? null : studentRecordList.stream()
                .filter(item -> Objects.nonNull(item.getSettlementDate()))
                .peek(item -> item.setInterval(LocalDateTimeUtils.betweenTwoTime( item.getSettlementDate(),currentDateTime, ChronoUnit.SECONDS)))
                .min(Comparator.comparing(StudentRecordDO::getInterval)).orElse(null);
        result = Objects.nonNull(studentRecordDO3) ? 3 : result;
        if (result > 0) {
            switch (result) {
                case 2 -> studentRecordDO = studentRecordDO2;
                case 3 -> studentRecordDO = studentRecordDO3;
            }
            studentInfoDTO.setCurrentClazzId(studentRecordDO.getClazzId());
            studentInfoDTO.setCurrentClazzName(studentRecordDO.getClazzName());
            studentInfoDTO.setStudentRecordId(studentRecordDO.getId());
        }
        log.info("【获取当前所在班级】满足条件：{}", result);
    }


    public static void convertToStudentClazzInfoDTO(StudentClazzInfoDTO clazzInfoDTO,
                                                    Map<Integer, List<StudentRecordDO>> map) {
        List<StudentRecordDO> list = map.get(clazzInfoDTO.getStudentId());
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        // LocalDateTime now =  LocalDateTime.now();
        List<StudentClazzRecordInfoDTO> recordInfoList = new ArrayList<>();
        for (StudentRecordDO studentRecordDO : list) {
            StudentClazzRecordInfoDTO clazzRecordInfoDTO = CustomBeanUtil.copyProperties(studentRecordDO, new StudentClazzRecordInfoDTO());
            // 支付类型
            clazzRecordInfoDTO.setPaymentType(EnumUtil.getBy(PaymentTypeEum::getName,studentRecordDO.getPaymentType() ) );
            // 是否升级
            clazzRecordInfoDTO.setRenewalFlag(Objects.nonNull(studentRecordDO.getRenewalFlag()) && studentRecordDO.getRenewalFlag() ==1);
            clazzRecordInfoDTO.setStartClazzDate(studentRecordDO.getStartDate());
            clazzRecordInfoDTO.setStudentRecordId(studentRecordDO.getId());
            // 合同状态 ,【contract_state】 这个字段暂时先返回一个静态值：“UNSIGNED” ，后续新EMS跟合同系统再处理
            clazzRecordInfoDTO.setContractState(ContractStateEnum.UNSIGNED);
            clazzRecordInfoDTO.setSuspensionFlag(studentRecordDO.getSuspensionFlag());
            clazzRecordInfoDTO.setDelayFlag(studentRecordDO.getDelayFlag());
            //            // 维护当前所在班级
            //            if (Objects.isNull(clazzInfoDTO.getCurrentClazzId())
            //                    && !studentRecordDO.getInDate().isAfter(now) && (Objects.isNull(studentRecordDO.getSettlementDate())
            //                    || !studentRecordDO.getSettlementDate().isBefore(now))) {
            //                clazzInfoDTO.setCurrentClazzId(studentRecordDO.getClazzId());
            //            }
            recordInfoList.add(clazzRecordInfoDTO);
        }
        StudentInfoDTO infoDTO =new StudentInfoDTO(clazzInfoDTO.getStudentId()) ;
        setCurrentClazz(infoDTO , map);
        clazzInfoDTO.setCurrentClazzId(infoDTO.getCurrentClazzId());
        clazzInfoDTO.setStudentRecords(recordInfoList);
        clazzInfoDTO.setStudentRecordId(infoDTO.getStudentRecordId());
    }

    public static StudentRecordInfoDTO convertToStudentRecordInfoDTO(StudentRecordDO recordDO) {
        StudentRecordInfoDTO studentRecordInfoDTO = CustomBeanUtil.copyProperties(recordDO, new StudentRecordInfoDTO());
        studentRecordInfoDTO.setStudentRecordId(recordDO.getId());
        // 支付类型
        studentRecordInfoDTO.setPaymentType(EnumUtil.getBy(PaymentTypeEum::getName,PaymentTypeEum.getEnumByCode(recordDO.getPaymentType()) )  );
        studentRecordInfoDTO.setRenewalFlag(Objects.nonNull(recordDO.getRenewalFlag()) && recordDO.getRenewalFlag() == 1);
        // 合同状态 ,【contract_state】 这个字段暂时先返回一个静态值：“UNSIGNED” ，后续新EMS跟合同系统再处理
        studentRecordInfoDTO.setContractState(ContractStateEnum.UNSIGNED);
        return studentRecordInfoDTO;

    }

    public static StudentRecordRefundInfoDTO wrapStudentRecordRefundInfoDTO(StudentRecord record,JournalDropout dropout) {
        StudentRecordRefundInfoDTO recordRefundInfoDTO = new StudentRecordRefundInfoDTO();
        recordRefundInfoDTO.setId(dropout.getId());
        recordRefundInfoDTO.setStudentRecordId(record.getId());
        recordRefundInfoDTO.setBizDate(dropout.getBizDate());
        recordRefundInfoDTO.setAmount(dropout.getAmount());
        recordRefundInfoDTO.setClazzId(dropout.getClazzId());
        recordRefundInfoDTO.setClazzName(dropout.getClazzName());
        recordRefundInfoDTO.setRemark(dropout.getRemark());
        recordRefundInfoDTO.setJournalRefundId(dropout.getJournalRefundId());
        recordRefundInfoDTO.setServiceDays(dropout.getServiceDays());
        recordRefundInfoDTO.setCompanyName(dropout.getCompanyName());
        recordRefundInfoDTO.setInvoiceFlag(dropout.getInvoiceFlag());
        recordRefundInfoDTO.setReasonDescription(dropout.getReasonDescription());
        recordRefundInfoDTO.setType(dropout.getType());
        recordRefundInfoDTO.setLoanFlag(dropout.getLoanFlag());
        recordRefundInfoDTO.setSpecialFlag(dropout.getSpecialFlag());
        recordRefundInfoDTO.setSettlementDays(dropout.getSettlementDays());
        recordRefundInfoDTO.setSettlementAmount(dropout.getSettlementAmount());
        return recordRefundInfoDTO;
    }

    /**
     * <p>
     * 统计各项指标，如：升级人数、重读人数、转班人数、退学人数、休学人数、签订合同人数、在班人数和班级总人数
     * </p>
     *
     * @param statisticsInfoDTO 需要返回的统计信息
     * @param recordCountList 学籍统计列表， 基于学籍 【来源】和【结课原因】
     * @param products 产品列表
     * @author zhouwei
     * @since 2024/3/18 11:11 AM
     **/
    public static void invokeStudentClazzStatisticsInfoDTO(StudentClazzStatisticsInfoDTO statisticsInfoDTO,
                                                           List<StudentRecordDO> recordCountList,
                                                           List<ProductDO> products) {
        StudentRecordDO recordDO = null;
        if (!CollectionUtils.isEmpty(recordCountList)) {
            // 升级人数
            recordDO = recordCountList.stream()
                    .filter(item -> ReferenceTypeEnum.RENEWAL.name().equalsIgnoreCase(item.getSettlementReason()))
                    .findFirst()
                    .orElse(null);
            statisticsInfoDTO.setRenewalCount(Objects.nonNull(recordDO) ? recordDO.getQuantity() : 0);
            // 重读人数
            recordDO = recordCountList.stream()
                    .filter(item -> ReferenceTypeEnum.REPEAT.name().equalsIgnoreCase(item.getSettlementReason()))
                    .findFirst()
                    .orElse(null);
            statisticsInfoDTO.setRepeatCount(Objects.nonNull(recordDO) ? recordDO.getQuantity() : 0);
            // 转班人数
            recordDO = recordCountList.stream()
                    .filter(item -> ReferenceTypeEnum.TRANSFER.name().equalsIgnoreCase(item.getSettlementReason()))
                    .findFirst()
                    .orElse(null);
            statisticsInfoDTO.setExchangeCount(Objects.nonNull(recordDO) ? recordDO.getQuantity() : 0);
            // 退学人数
            recordDO = recordCountList.stream()
                    .filter(item -> ReferenceTypeEnum.DROPOUT.name().equalsIgnoreCase(item.getSettlementReason()))
                    .findFirst()
                    .orElse(null);
            statisticsInfoDTO.setDropoutCount(Objects.nonNull(recordDO) ? recordDO.getQuantity() : 0);
            // 休学人数
            recordDO = recordCountList.stream()
                    .filter(item -> ReferenceTypeEnum.SUSPENSION.name().equalsIgnoreCase(item.getSettlementReason()))
                    .findFirst()
                    .orElse(null);
            statisticsInfoDTO.setSuspensionCount(Objects.nonNull(recordDO) ? recordDO.getQuantity() : 0);
            // 签订合同人数
            statisticsInfoDTO.setSignupCount(0);
            // 在班人数
            recordDO = recordCountList.stream()
                    .filter(item -> Objects.isNull(item.getSettlementReason()))
                    .findFirst()
                    .orElse(null);
            statisticsInfoDTO.setInClazzCount(Objects.nonNull(recordDO) ? recordDO.getQuantity() : 0);
        }
        // 班级容量
        if (!CollectionUtils.isEmpty(products)) {
            statisticsInfoDTO.setClassroomCapacity(products.get(0).getQuantity());
        }
    }
}
